﻿using System;
using System.ComponentModel;
using System.Windows;
using AddressManager.Common.ViewModel;
using AddMan = AddressManager.Services.AddressManagerService;
using Maps = Microsoft.Maps.MapControl;
using AddressManager.Services.GeocodeService;

namespace AddressManager.Business.ViewModels
{
    public class AddContactViewModel : AbstractViewModel
    {
        private const string MapKey = "AjUFz78ukl2NOKN-ZF8o7JWWfV-WJ-v7jNPuMGTVb26qVbI7a2kAABnvjiMwRzkY";

        readonly GeocodeServiceClient _geocodeService;
        readonly AddMan.AddressManagerWebServiceClient _addManService;

        private AddMan.Contact _contact2Add;

        public AddContactViewModel()
        {
            _geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            _geocodeService.GeocodeCompleted += GeocodeService_GeocodeCompleted;

            _addManService = new AddMan.AddressManagerWebServiceClient("CustomBinding_AddressManagerWebService");
            _addManService.AddNewContactCompleted += AddManServiceAddNewContactCompleted;
            _addManService.ContactExistsCompleted += AddManServiceContactExistsCompleted;
        }

        #region DataBinding

        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set { SetProperty(this, x => x.FirstName, ref _firstName, value); }
        }

        private string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set { SetProperty(this, x => x.LastName, ref _lastName, value); }
        }

        private DateTime _birthday;
        public DateTime Birthday
        {
            get { return _birthday; }
            set { SetProperty(this, x => x.Birthday, ref _birthday, value); }
        }

        private string _email;
        public string Email
        {
            get { return _email; }
            set { SetProperty(this, x => x.Email, ref _email, value); }
        }

        private string _msnAddress;
        public string MsnAddress
        {
            get { return _msnAddress; }
            set { SetProperty(this, x => x.MsnAddress, ref _msnAddress, value); }
        }

        private string _icqNumber;
        public string IcqNumber
        {
            get { return _icqNumber; }
            set { SetProperty(this, x => x.IcqNumber, ref _icqNumber, value); }
        }

        private string _street;
        public string Street
        {
            get { return _street; }
            set { SetProperty(this, x => x.Street, ref _street, value); }
        }

        private string _number;
        public string Number
        {
            get { return _number; }
            set { SetProperty(this, x => x.Number, ref _number, value); }
        }

        private string _postalCode;
        public string PostalCode
        {
            get { return _postalCode; }
            set { SetProperty(this, x => x.PostalCode, ref _postalCode, value); }
        }

        private string _city;
        public string City
        {
            get { return _city; }
            set { SetProperty(this, x => x.City, ref _city, value); }
        }

        private Maps.Location _location;
        public Maps.Location Location
        {
            get { return _location; }
            set { SetProperty(this, x => x.Location, ref _location, value); }
        }

        private Visibility _pinVisibility;
        public Visibility PinVisibility
        {
            get { return _pinVisibility; }
            set { SetProperty(this, x => x.PinVisibility, ref _pinVisibility, value); }
        }

        #endregion

        #region Methods

        public void Reset()
        {
            FirstName = string.Empty;
            LastName = string.Empty;
            Birthday = DateTime.Today;
            Email = string.Empty;
            MsnAddress = string.Empty;
            IcqNumber = string.Empty;
            Street = string.Empty;
            Number = string.Empty;
            PostalCode = string.Empty;
            City = string.Empty;
            PinVisibility = Visibility.Collapsed;

            OnPinSetted();
        }

        #region AddressSearch

        public void SearchAddress()
        {
            var request = BuildRequest();

            if (request.Query != string.Empty)
            {
                _geocodeService.GeocodeAsync(request);
            }
            else
            {
                Location = new Maps.Location(0, 0);
                PinVisibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// Builds the request string for the geocode web service
        /// </summary>
        /// <returns>Request string</returns>
        private GeocodeRequest BuildRequest()
        {
            var geocodeRequest = new GeocodeRequest { Credentials = new Credentials { ApplicationId = MapKey } };

            // Set the credentials using a valid Bing Maps key

            // Set the full address query
            if (Street != string.Empty && Number != string.Empty && PostalCode != string.Empty && City != string.Empty)
            {
                geocodeRequest.Query = string.Format("{0} {1}, {2} {3}", _street, _number, _postalCode, _city);
            }
            else
            {
                geocodeRequest.Query = string.Empty;
            }

            // Set the options to only return high confidence results 
            var filters = new ConfidenceFilter[1];
            filters[0] = new ConfidenceFilter { MinimumConfidence = Confidence.High };

            var geocodeOptions = new GeocodeOptions { Filters = filters };

            geocodeRequest.Options = geocodeOptions;

            return geocodeRequest;
        }

        private void GeocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
        {
            GeocodeResponse geocodeResponse = e.Result;

            if (geocodeResponse.Results.Length > 0)
            {
                Location = new Maps.Location(geocodeResponse.Results[0].Locations[0].Latitude, geocodeResponse.Results[0].Locations[0].Longitude);
                PinVisibility = Visibility.Visible;
            }

            OnPinSetted();
        }

        #endregion

        #region ContactAdding

        public void AddNewContact()
        {
            var c = new AddMan.Contact
            {
                FirstName = FirstName,
                LastName = LastName,
                Birthday = Birthday,
                Email = Email,
                Msn = MsnAddress,
                Icq = IcqNumber
            };

            var a = new AddMan.Address
            {
                Street = Street,
                Number = Number,
                PostalCode = PostalCode,
                City = City,
                LocationX = Location.Latitude,
                LocationY = Location.Longitude
            };

            c.Address = a;

            _contact2Add = c;

            _addManService.ContactExistsAsync(c.FirstName, c.LastName);
        }

        void AddManServiceContactExistsCompleted(object sender, AddMan.ContactExistsCompletedEventArgs e)
        {
            if (e.Result)
            {
                OnErrorRaised(string.Format("Der Kontakt {0} {1} ist bereits vorhanden.", _contact2Add.FirstName, _contact2Add.LastName));
            }
            else
            {
                _addManService.AddNewContactAsync(_contact2Add, _contact2Add);    
            }
        }

        void AddManServiceAddNewContactCompleted(object sender, AsyncCompletedEventArgs e)
        {
            var addedContact = (AddMan.Contact)e.UserState;

            OnEntityAdded(string.Format("Der Kontakt {0} {1} wurde erfolgreich hinzugefügt.", addedContact.FirstName, addedContact.LastName));
        }

        #endregion

        #endregion
    }
}